var cache = {};
var tree = {
    getAttributeValue: function (attribute, instance, name) {
        if (!instance || !instance._id || !instance.body || !name) return null;
        var node = checkMap(instance)[name];
        return node[attribute];
    },

    setAttributeValue: function (attribute, instance, name, value) {
        if (!instance || !instance._id || !instance.body || !name) return null;
        var node = checkMap(instance)[name];
        return node[attribute] = value;
    },
    deleteAttribute: function (attribute, instance, name) {
        if (!instance || !instance._id || !instance.body || !name) return null;
        var node = checkMap(instance)[name];
        delete node[attribute];
    },
    getNode: function (instance, name) {
        if (!instance || !instance._id || !instance.body || !name) return null;
        var node = checkMap(instance)[name];
        return node;
    },
    checkNodeExist: function (instance, name) {
        if (!instance || !instance._id || !instance.body || !name) return null;
        var node = checkMap(instance)[name];
        if (node) {
            return true;
        }
        else {
            return false;
        }
    },
    drawNode: function (total, parent, dump, name, begin) {
        if (total >= 1) {
            var array = [];
            parent[name] = {
                "total": total,
                "begin": begin
            };
            for (var i = 2; i < total + 1; i++) {
                var add = dumplicateNode(dump, i - 1, begin);
                if (add instanceof Array) {
                    for (var j = 0; j < add.length; j++) {
                        array.push(add[j]);
                    }
                }
                else {
                    array.push(add);
                }
            }
            if (dump instanceof Array) {
                for (var i = 0; i < dump.length; i++) {
                    dump[i].text = dump[i].text.replace('n', begin);
                    dump[i].name = dump[i].name.replace('n', begin);
                }
            }
            else {
                dump.text = dump.text.replace('n', begin);
                dump.name = dump.name.replace('n', begin);
            }
            for (var i = 0; i < array.length; i++) {
                parent.children.push(array[i]);
            }
        }
    },
    deleteNode: function (instance, parentName, childName) {
        if (parentName == ".") {
            var children = instance.body;
            for (var i = 0; i < children.length; i++) {
                var child = children[i];
                if (child.name == childName) {
                    children.splice(i, 1);
                    break;
                }
            }
        }
        else {
            var parentNode = tree.getNode(instance, parentName);
            var children = parentNode.children;
            for (var i = 0; i < children.length; i++) {
                var child = children[i];
                if (child.name == childName) {
                    children.splice(i, 1);
                    break;
                }
            }
        }
    },
    expire: function (instance) {
        if (!instance || !instance._id) return null;
        delete cache[instance._id];
    }
};

function checkMap(instance) {
    var treeMap;
    if (cache[instance._id]) {
        if (cache[instance._id]._obj !== instance) {
            delete cache[instance._id];
        } else {
            treeMap = cache[instance._id];
        }
    }
    if (!treeMap) {
        treeMap = {_obj: instance};
        buildMap(instance.body, [], treeMap);
        cache[instance._id] = treeMap;
    }
    return treeMap;
}

function buildMap(node, path, map) {
    if (node instanceof Array) {
        for (var i = 0; i < node.length; i++) {
            buildMap(node[i], path, map);
        }
    } else {
        path.push(node.name);
        map[path.join(".")] = node;
        if (node.children) {
            for (var i = 0; i < node.children.length; i++) {
                buildMap(node.children[i], path, map);
            }
        }
        path.pop();
    }
}

function dumplicateNode(dump, index, begin) {
    var d = $.extend(true, dump instanceof Array ? [] : {}, dump);
    if (dump instanceof Array) {
        var array = [];
        for (var i = 0; i < d.length; i++) {
            d[i].text = d[i].text.replace('n', index + begin);
            d[i].name = d[i].name.replace('n', index + begin);
            array.push(d[i]);
        }
        return array;
    }
    else {
        d.text = d.text.replace('n', index + begin);
        d.name = d.name.replace('n', index + begin);
        return d;
    }
}
